package com.juku2024.juku.tools

import android.text.TextUtils
import android.util.Base64
import java.io.ByteArrayOutputStream
import java.lang.Exception
import java.nio.charset.StandardCharsets
import java.security.KeyFactory
import java.security.PrivateKey
import java.security.PublicKey
import java.security.interfaces.RSAPublicKey
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec

object EncryptionUtils {

    /**
     * 加解密算法/工作模式/填充方式
     */
    private const val RSA = "RSA/ECB/PKCS1Padding"

    /**
     * 加密
     * @param sSrc 加密的明文
     * @throws Exception
     */
    @Throws(Exception::class)
    fun aesEncrypt(sSrc: String?): String? {
        if (sSrc == null) return null
        val token = SPUtil.instance.token
        val sKey = token.subSequence(0, 16).toString()
        val iv = token.subSequence(16, 32).toString()
        if (checkFiled(sSrc, sKey, iv)) {
            return null
        }
        val raw = sKey.toByteArray()
        val skeySpec = SecretKeySpec(raw, "AES")
        val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
        val iv1 = IvParameterSpec(iv.toByteArray())
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv1)
        val encrypted = cipher.doFinal(sSrc.toByteArray())
        return com.juku2024.juku.tools.Base64.encodeBytes(encrypted)
    }

    /**
     * 解密
     * @throws Exception
     */
    @Throws(Exception::class)
    fun aesDecrypt(data: String?, aseKey: String?): String? {
        if (data == null || aseKey == null || aseKey.length < 32) return null
        return try {
            val sKey = aseKey.substring(0, 16)
            val iv = aseKey.substring(16, 32)
            if (checkFiled(data, sKey, iv)) {
                return null
            }
            //先用Base64解码
            val byte1 = com.juku2024.juku.tools.Base64.decode(data.toByteArray())
            val ivSpec = IvParameterSpec(iv.toByteArray())
            val key = SecretKeySpec(sKey.toByteArray(), "AES")
            val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
            cipher.init(Cipher.DECRYPT_MODE, key, ivSpec)
            assert(byte1 != null)
            val ret = cipher.doFinal(byte1)
            String(ret, StandardCharsets.UTF_8)
        } catch (ex: Exception) {
            println(ex)
            null
        }
    }

    /**
     * 解密
     *
     * @param sSrc 接收到的加密过后的字符串（带解密密文）
     * @param sKey 秘钥
     * @return
     * @throws Exception
     */
    @Throws(Exception::class)
    fun aesDecrypt(sSrc: String?): String? {
        if (sSrc == null) return null
        val token = SPUtil.instance.token
        if (token.length != 16) return null
        return try {
            val sKey = token.substring(0, 16)
            val iv = token.substring(16, 32)
            if (checkFiled(sSrc, sKey, iv)) {
                return null
            }
            //先用Base64解码
            val byte1 = com.juku2024.juku.tools.Base64.decode(sSrc.toByteArray())
            val ivSpec = IvParameterSpec(iv.toByteArray())
            val key = SecretKeySpec(sKey.toByteArray(), "AES")
            val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
            cipher.init(Cipher.DECRYPT_MODE, key, ivSpec)
            assert(byte1 != null)
            val ret = cipher.doFinal(byte1)
            String(ret, StandardCharsets.UTF_8)
        } catch (ex: Exception) {
            println(ex)
            null
        }
    }

    /**
     * RSA使用私钥解密
     * */
    fun rsaDecrypt(encrypted: String?): String? {
        try {
            if (TextUtils.isEmpty(encrypted)) return null
            // 得到公钥对象
            val privateKey = AppUtils.method02()
            if (TextUtils.isEmpty(privateKey)) return null
            // 将要解密的数据，进行 Base64 解码
            val encryptedData: ByteArray = base64Decode(encrypted!!) ?: return null
            // 创建 Cipher 对象，用来解密
            val cipher = Cipher.getInstance(RSA)
            // 初始化 Cipher 对象，解密模式
            val key = getPrivateKey(privateKey) ?: return null
            cipher.init(Cipher.DECRYPT_MODE, key)
            val inputLen = encryptedData.size
            // 保存解密的数据
            val out = ByteArrayOutputStream()
            var offSet = 0
            var i = 0
            var cache: ByteArray
            // 对数据分段解密
            while (inputLen - offSet > 0) {
                cache = if (inputLen - offSet > 128) {
                    cipher.doFinal(encryptedData, offSet, 128)
                } else {
                    cipher.doFinal(encryptedData, offSet, inputLen - offSet)
                }
                // 将解密后的数据保存到内存
                out.write(cache, 0, cache.size)
                i++
                offSet = i * 128
            }
            val decryptedData: ByteArray = out.toByteArray()
            out.close()
            return String(decryptedData, StandardCharsets.UTF_8)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /** 使用公钥加密  */
    @Throws(Exception::class)
    fun rsaEncrypt(data: String?): String? {
        if (TextUtils.isEmpty(data)) return null
        // 得到公钥对象
        val publicKey = AppUtils.method01()
        if (TextUtils.isEmpty(publicKey)) return null
        try {
            // base64编码的公钥
            val decoded = base64Decode(publicKey)
            val pubKey: RSAPublicKey = KeyFactory.getInstance("RSA").generatePublic(X509EncodedKeySpec(decoded)) as RSAPublicKey
            // RSA加密
            val cipher = Cipher.getInstance(RSA)
            cipher.init(Cipher.ENCRYPT_MODE, pubKey)
            return base64Encode(cipher.doFinal(data!!.toByteArray()))
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /** 使用公钥加密  */
    @Throws(Exception::class)
    fun rsaEncrypt(): String? {
        val token = SPUtil.instance.token
        if (TextUtils.isEmpty(token)) {
            return null
        }
        // 得到公钥对象
        val publicKey = AppUtils.method01()
        if (TextUtils.isEmpty(publicKey)) return null
        try {
            // base64编码的公钥
            val decoded = base64Decode(publicKey)
            val pubKey: RSAPublicKey = KeyFactory.getInstance("RSA").generatePublic(X509EncodedKeySpec(decoded)) as RSAPublicKey
            // RSA加密
            val cipher = Cipher.getInstance(RSA)
            cipher.init(Cipher.ENCRYPT_MODE, pubKey)
            return base64Encode(cipher.doFinal(token.toByteArray()))
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * 将 字节数组 转换成 Base64 编码
     * 用Base64.DEFAULT模式会导致加密的text下面多一行（在应用中显示是这样）
     */
    private fun base64Encode(data: ByteArray?): String? {
        return Base64.encodeToString(data, Base64.NO_WRAP)
    }


    /**
     * 将 Base64 字符串 解码成 字节数组
     */
    private fun base64Decode(data: String): ByteArray? {
        return Base64.decode(data, Base64.NO_WRAP)
    }

    /**
     * 获取 PrivateKey 对象
     *
     * @param prvKey 私钥，PKCS8 格式
     */
    private fun getPrivateKey(prvKey: String): PrivateKey? {
        try {
            // 私钥数据
            val privateKey: ByteArray? = base64Decode(prvKey)
            // 创建 PrivateKey 对象并返回
            return KeyFactory.getInstance("RSA")
                .generatePrivate(PKCS8EncodedKeySpec(privateKey))
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    private fun checkFiled(sSrc: String?, sKey: String?, iv: String?): Boolean {
        if (sSrc == null) {
            print("src不能为空null")
            return true
        }
        if (sKey?.length != 16) {
            print("Key的长度不是16位")
            return true
        }
        if (iv?.length != 16) {
            print("iv的长度不是16位")
            return true
        }
        return false
    }


    /**
     * 获取 PrivateKey 对象
     */
    private fun getPrivateKey(): PublicKey? {
        try {
            // 私钥数据
            val keyFactory = KeyFactory.getInstance("RSA")
            val keySpec =
                X509EncodedKeySpec(base64Decode(AppUtils.method01()))
            // 创建 PrivateKey 对象并返回
            return keyFactory.generatePublic(keySpec)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }
    /**
     * RSA最大解密密文大小
     */
    private val MAX_DECRYPT_BLOCK = 128
    /**
     * 编码
     */
    private val CHARSET_UTF8 = StandardCharsets.UTF_8
    /**
     * 使用 公钥 将加密后的 Base64 字符串进行分段解密
     *
     * @param encryptBase64Data 加密后的 Base64 字符串
     * @return 解密后的明文，解密失败返回 null
     */
    fun decryptByPublicKey(encryptBase64Data: String): String? {
        try {
            // 将要解密的数据，进行 Base64 解码
            val encryptedData: ByteArray = base64Decode(encryptBase64Data)?:return null
            // 创建 Cipher 对象，用来解密
            val cipher = Cipher.getInstance(RSA)
            // 初始化 Cipher 对象，解密模式
            cipher.init(Cipher.DECRYPT_MODE, getPrivateKey())
            val inputLen = encryptedData.size
            // 保存解密的数据
            val out = ByteArrayOutputStream()
            var offSet = 0
            var i = 0
            var cache: ByteArray
            // 对数据分段解密
            while (inputLen - offSet > 0) {
                cache = if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK)
                } else {
                    cipher.doFinal(encryptedData, offSet, inputLen - offSet)
                }
                // 将解密后的数据保存到内存
                out.write(cache, 0, cache.size)
                i++
                offSet = i * MAX_DECRYPT_BLOCK
            }
            val decryptedData = out.toByteArray()
            out.close()
            return String(decryptedData, CHARSET_UTF8)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }
}